package com.wispx.gateway.core.request;

import com.wispx.gateway.config.pojo.ServiceDefinition;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import lombok.Data;
import org.asynchttpclient.Request;
import org.asynchttpclient.RequestBuilder;

import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 网关请求
 */
@Data
public class GatewayRequest {

    private String id; // 流水号
    private ServiceDefinition serviceDefinition; // 服务
    private long beginTime; // 进入网关时间戳
    private Charset charset; // 字符集
    private String clientIp; // 客户端的IP，用来做白名单、限流
    private String host; // 请求的地址
    private String path; // 请求的路径
    private String uri; // 请求的 uri，如： user/login/xxx?k1=v1&k2=v2
    private HttpMethod method; // 请求的方式，GET/POST/PUT
    private String contentType; // 请求的类型 application/json;
    private HttpHeaders headers; // 请求头消息
    private QueryStringDecoder queryStringDecoder; // 参数解码器
    private FullHttpRequest fullHttpRequest; // fullHttpRequest
    private RequestBuilder requestBuilder; // 构建下游请求
    private String body; // 请求体
    private Map<String, Cookie> cookieMap; // 请求 Cookie
    private Map<String, List<String>> postParameters; // post请求的参数
    private String modifyScheme; // 发给下游的 scheme，默认为 http://
    private String modifyHost; // 发给下游的 host
    private String modifyPath; // 发给下游的 path
    private boolean isGray; // 是否灰度

    public GatewayRequest(ServiceDefinition serviceDefinition,
                          Charset charset,
                          String clientIp,
                          String host,
                          String uri,
                          HttpMethod method,
                          String contentType,
                          HttpHeaders headers,
                          FullHttpRequest fullHttpRequest) {
        this.id = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss")) + "---" + UUID.randomUUID();
        this.serviceDefinition = serviceDefinition;
        this.beginTime = System.currentTimeMillis();
        this.charset = charset;
        this.clientIp = clientIp;
        this.host = host;
        this.uri = uri;
        this.method = method;
        this.contentType = contentType;
        this.headers = headers;
        this.fullHttpRequest = fullHttpRequest;

        // user/login/xxx?k1=v1&k2=v2
        this.queryStringDecoder = new QueryStringDecoder(uri, charset);
        this.path = queryStringDecoder.path(); //  user/login/xxx
        this.modifyHost = host;
        this.modifyPath = path;
        this.modifyScheme = "http://";

        // AsyncHttpClient 使用的请求
        this.requestBuilder = new RequestBuilder();
        this.requestBuilder.setMethod(method.name());
        this.requestBuilder.setHeaders(headers);
        this.requestBuilder.setQueryParams(queryStringDecoder.parameters()); // k1=v1&k2=v2
        ByteBuf contentBuffer = fullHttpRequest.content();
        if (Objects.nonNull(contentBuffer)) {
            this.requestBuilder.setBody(contentBuffer.nioBuffer());
            contentBuffer.release();
        }
    }

    /**
     * 构建 AsyncHttpClient 发送的请求
     */
    public Request build() {
        // http:// + host + user/login/xxx
        return requestBuilder.setUrl(modifyScheme + modifyHost + modifyPath).build();
    }

    public Cookie getCookie(String cookieName) {
        if (cookieMap != null && !cookieMap.isEmpty()) {
            return cookieMap.get(cookieName);
        }
        // 从请求头获取 cookie
        String cookies = headers.get(HttpHeaderNames.COOKIE);
        if (cookies == null || cookies.isBlank()) {
            return null;
        }
        Set<Cookie> cookieSet = ServerCookieDecoder.STRICT.decode(cookies); // 解码
        cookieMap = new HashMap<>();
        for (Cookie cookie : cookieSet) {
            cookieMap.put(cookieName, cookie);
        }
        return cookieMap.get(cookieName);
    }

}
